﻿using Microsoft.AspNetCore.Http;
using Microsoft.Extensions.Logging;
using Newtonsoft.Json;
using Rw.Core.Common;
using SqlSugar;
using System;
using System.Collections.Generic;
using System.Diagnostics;
using System.Linq;
using System.Text;
using System.Text.RegularExpressions;
using System.Threading.Tasks;
using WH.Common.Config;
using WH.Common.Handler;
using WH.Contracts.Systems.Login;
using WH.Model.Systems;

namespace WH.Services.Middleware
{
    /// <summary>
    /// 操作日志记录中间件
    /// </summary>
    public class OperationLogMiddleware
    {
        /// <summary>
        /// 
        /// </summary>
        public readonly RequestDelegate _next;
        private readonly ILogger<OperationLogMiddleware> _logger;
        private readonly IConfigurationCenter _configurationCenter;
        private readonly ISqlSugarClient _db;

        /// <summary>
        /// 
        /// </summary>
        public OperationLogMiddleware(RequestDelegate next, ILogger<OperationLogMiddleware> logger, IConfigurationCenter configurationCenter, ISqlSugarClient sqlSugarClient)
        {
            _next = next;
            _logger = logger;
            _db = sqlSugarClient;// serviceProvider.CreateScope().ServiceProvider.GetRequiredService<ISqlSugarClient>();
            _configurationCenter = configurationCenter;
        }



        public async Task InvokeAsync(HttpContext context)
        {
            if (_configurationCenter.OperationLogOptions.Enable)
            {
                if (!_configurationCenter.OperationLogOptions.Methods?.Split(',').Contains(context.Request.Method, StringComparer.OrdinalIgnoreCase) == true)
                {
                    await _next(context);
                    return;
                }

                var ignores = _configurationCenter.OperationLogOptions.IgnorePaths?.Select(x => x).ToList() ?? new List<string>();

                ignores.AddRange(igns);

                var requestUrl = (context.Request.Path.Value ?? "");

                if (ignores.Contains(requestUrl, StringComparer.OrdinalIgnoreCase))
                {
                    await _next(context);
                    return;
                }
                //集采盒子服务上传文件
                if (requestUrl.Equals("/BizCollectboxFile/Save") || requestUrl.Equals("/Collectbox/OnLine"))
                {
                    await _next(context);
                    return;
                }
                context.Request.EnableBuffering();

                var request = context.Request;

                var response = context.Response;

                // 计时器
                Stopwatch _stopwatch = new Stopwatch();
                _stopwatch.Start();

                string operation = "";
                string describe = "";
                string useraccount = "";
                string? orgId = "";

                try
                {
                    string ipAddress = context.Connection.RemoteIpAddress?.ToString() ?? "";
                    var loginModel = new JwtTokenModel();

                    try
                    {
                        loginModel = JwtTokenHandler.LoginModel;
                    }
                    catch (Exception ex) { }


                    _stopwatch.Stop();

                    if (context.Request.Method.ToUpper().Equals("OPTIONS", StringComparison.OrdinalIgnoreCase) == false)
                    {
                        var requestObject = "";
                        var responseObject = "";

                        if (_configurationCenter.OperationLogOptions.LogBodyEnable)
                        {
                            // 开启数据缓存
                            context.Request.EnableBuffering();
                            using (MemoryStream memoryStream = new())
                            {
                                // 复制Body数据到缓存
                                await context.Request.Body.CopyToAsync(memoryStream);
                                context.Request.Body.Position = 0;
                                using (StreamReader streamReader = new(memoryStream))
                                {
                                    memoryStream.Position = 0;
                                    // 读取Body数据
                                    string? body = await streamReader.ReadToEndAsync();
                                    requestObject = body;

                                    if (requestUrl.Contains("login"))
                                    {
                                        var sr = new StreamReader(request.Body);

                                        var content = await sr.ReadToEndAsync();

                                        operation = "登录";

                                        var loginInput = JsonConvert.DeserializeObject<LoginInputDto>(content);
                                        useraccount = loginInput?.UserAccount ?? "";

                                        if (loginInput is not null)
                                        {
                                            loginInput.Password = "";
                                        }
                                        requestObject = JsonConvert.SerializeObject(loginInput);


                                        request.Body.Position = 0;

                                        var user = await _db.Queryable<UserEntity>().Where(x => x.Account == useraccount).FirstAsync();

                                        orgId = user?.OrganizationId;
                                    }
                                    else
                                    {
                                        switch (context.Request.Method)
                                        {
                                            case "GET":
                                                operation = "查看";
                                                break;
                                            case "POST":
                                                operation = "新增";
                                                break;
                                            case "PUT":
                                                operation = "修改";
                                                break;
                                            case "DELETE":
                                                operation = "删除";
                                                break;
                                            default:
                                                break;
                                        }

                                        orgId = loginModel?.OrganizationId;
                                    }
                                }
                            }


                            // 原Body缓存
                            Stream originalBody = context.Response.Body;
                            try
                            {
                                // 新Body缓存
                                using (MemoryStream memoryStream = new())
                                {
                                    // Body赋值为新Body缓存
                                    context.Response.Body = memoryStream;
                                    // 向下执行（等待返回）
                                    await _next.Invoke(context);
                                    // 原Body缓存赋值为新Body缓存
                                    memoryStream.Position = 0;
                                    await memoryStream.CopyToAsync(originalBody);

                                    using (StreamReader streamReader = new(memoryStream))
                                    {
                                        // 读取Body数据
                                        memoryStream.Position = 0;
                                        string body = await streamReader.ReadToEndAsync();
                                        // 日志
                                        responseObject = body;
                                    }
                                }
                            }
                            finally
                            {
                                // Body重新赋值为原始Body缓存
                                context.Response.Body = originalBody;
                            }
                        }
                        else
                        {
                            await _next.Invoke(context);
                        }
                        var log = new SysOperationLogEntity()
                        {
                            Id = Snowflake.GetNewId(),
                            IpAddress = ipAddress,
                            Method = context.Request.Method,
                            OperateType = operation,
                            OperatorId = loginModel?.UserId,
                            OrganizationId = !string.IsNullOrWhiteSpace(orgId) ? orgId : loginModel?.OrganizationId ?? string.Empty,
                            Platform = string.Empty,
                            IsSuccess = context.Response.StatusCode == 200,
                            StatusCode = context.Response.StatusCode,
                            RequestUrl = requestUrl,
                            Describe = describe,
                            Stopwatch = _stopwatch.ElapsedMilliseconds,
                            UserAccount = string.IsNullOrWhiteSpace(useraccount) ? loginModel?.UserAccount : useraccount,
                            RequestObject = requestObject,
                            ResponseObject = responseObject,
                            CreatedTime = DateTime.Now,
                        };

                        await _db.Insertable(log).ExecuteCommandAsync();
                    }
                    else
                    {
                        await _next.Invoke(context);
                    }
                }
                catch (Exception ex)
                {
                    await _next.Invoke(context);
                }

                //context.Request.EnableBuffering();
                //Stream originalBody = context.Response.Body;

                //try
                //{
                //    // 存储请求数据
                //    await RequestDataLog(context);

                //    using (var ms = new MemoryStream())
                //    {
                //        context.Response.Body = ms;

                //        await _next(context);

                //        // 存储响应数据
                //        ResponseDataLog(context.Response, ms);

                //        ms.Position = 0;
                //        await ms.CopyToAsync(originalBody);

                //    }

                //}
                //catch (Exception ex)
                //{
                //    // 记录异常
                //    //ErrorLogData(context.Response, ex);
                //}
                //finally
                //{
                //    context.Response.Body = originalBody;
                //}
            }
            else
            {
                await _next(context);
            }
        }


        private async Task RequestDataLog(HttpContext context)
        {
            var request = context.Request;
            var sr = new StreamReader(request.Body);

            var content = $" QueryData:{request.Path + request.QueryString}\r\n BodyData:{await sr.ReadToEndAsync()}";

            if (!string.IsNullOrEmpty(content))
            {

                _logger.LogInformation("--------------------------------\r\n" +
                  "RequestDataLog:" + DateTime.Now + "|\r\n" +
                  "token:" + context.Request.Headers["Authorization"].ToString().Replace("Bearer ", "") + "|\r\n" +
                String.Join("\r\n", new string[] { "Request Data:", content }) + "\r\n");
                //LogLock.OutSql2Log("RequestResponseLog", new string[] { "Request Data:", content });

                request.Body.Position = 0;
            }
        }

        private void ResponseDataLog(HttpResponse response, MemoryStream ms)
        {
            ms.Position = 0;
            //byte[] bytes = ms.ToArray(); System.Text.Encoding.UTF8.GetString(bytes, 0, bytes.Length)
            var ResponseBody = new StreamReader(ms).ReadToEnd();

            // 去除 Html
            var reg = "<[^>]+>";
            var isHtml = Regex.IsMatch(ResponseBody, reg);

            if (!string.IsNullOrEmpty(ResponseBody))
            {
                _logger.LogInformation("--------------------------------\r\n" +
                  "ResponseDataLog:" + DateTime.Now + "|" + response.StatusCode + "|\r\n" +
                   String.Join("\r\n", new string[] { "Response Data:", ResponseBody }) + "\r\n");
            }
        }

        private List<string> igns = new List<string> {
            "/locations/AreaMemberCount",
            "/locations/GetFix",
            "/locations/GetRealtime"
        };
    }
}

